#include "TDAClienteCorreo.h"
#include "TDACorreo.h"
#include "TDAServidorInseguro.h"
#include "TDAListaDestinatarios.h"

#include <time.h>
#include <stdlib.h>
#include <string.h>

/* Definicios para hacer referencia a estados de conexion. */
#define NOT_CONNECTED 0
#define CONNECTED 1

#define RCV_NO_MSG 1
#define RCV_MSG_SUCCESS 0
#define RCV_MSG_ERROR 2

/* Comienzo de funciones auxiliares */

/*
 * Genera una clave aleatoria para usar en la encriptacion
 *
 * Parametros:
 * clave	un char* que apunta a un buffer donde se copiara la clave generada
 *
 * Valor de retorno:
 * N/A
 *
 * PRE: clave apunta a una zona de memoria valida con espacio suficiente para contener MAX_KEY_LEN caracteres y ademas el caracter terminador de cadena
 * POST: se ha generado clave para encriptacion y se la ha copiado en clave
 *
 */


/* Fin de funciones auxiliares */

void crearClienteCorreo(TDAClienteCorreo* clienteCorreo, char* direcUsr) {

    strcpy(clienteCorreo->direccion,direcUsr);

}

void destruirClienteCorreo(TDAClienteCorreo* clienteCorreo) {

    clienteCorreo->servidor = NULL;
	clienteCorreo->estadoConexion = NOT_CONNECTED;

}

void getDirecUsr(TDAClienteCorreo clienteCorreo, char* direcUsr) {
	strcpy(direcUsr, clienteCorreo.direccion);
}

void enviarClave(TDAClienteCorreo clienteCorreo, TDACanalSeguro* canalSeguro) {
    setContenido(canalSeguro, clienteCorreo.clave);
}

void obtenerClave(TDAClienteCorreo* clienteCorreo, TDACanalSeguro canalSeguro) {
    getContenido(canalSeguro, clienteCorreo->clave);
}

int conectar(TDAClienteCorreo* clienteCorreo, TDAServidorInseguro* servidorInseguro) {

	clienteCorreo->servidor = servidorInseguro;
	clienteCorreo->estadoConexion = CONNECTED;

	return 0;
}

int estaConectado(TDAClienteCorreo clienteCorreo) {

	if ( clienteCorreo.estadoConexion ) return CONNECTED;
	return NOT_CONNECTED;
}

void desconectar(TDAClienteCorreo* clienteCorreo) {
    clienteCorreo->estadoConexion = NOT_CONNECTED;
}

int enviarCorreo(TDAClienteCorreo *clienteCorreo, TDACorreo correo) {

    /* Simplemente para facilitar la sintaxis al acceder a los         *
     * elementos del servidor.
     */
    TDAServidorInseguro *aux = NULL;

    /* Defino una variable auxiliar para el campos del correo, si bien *
     * puedo acceder directamente con "correo.<attr>" es recomendable  *
     * no tener interaccion directa con el correo y valerse de los     *
     * getterS correspondientes.
     */
    char cuerpo[MAX_BODY_SIZE] = {};
    int estado;


    aux = clienteCorreo->servidor;

    getTextoCuerpo(correo, cuerpo);

    encriptarVignere(cuerpo, clienteCorreo->clave, cuerpo);

    setTextoCuerpo( &correo, cuerpo);
    setRemitente(&correo, clienteCorreo->direccion);

    estado = agregarCorreo(clienteCorreo->servidor, correo);

 	return estado;
}

int recibirProximoCorreo(TDAClienteCorreo clienteCorreo, TDACorreo* correo) {

	TDAServidorInseguro *aux;

    aux = clienteCorreo.servidor;

    if ( !(obtenerProximoCorreo(clienteCorreo.servidor,clienteCorreo.direccion,correo)) ){
        desencriptarVignere(correo->cuerpo,clienteCorreo.clave,correo->cuerpo);
        return EXIT_SUCCESS;
    }else{
        return NO_MESSAGES;
    }
}



int obtenerTodos(TDAClienteCorreo cliente, TListaCorreo* correos){

    TCola colaCorreos;
    TDACorreo correo;
    TDAServidorInseguro *aux = NULL;
    int sizeCorreo,cantCorreos;

    sizeCorreo = sizeof (TDACorreo);
    aux = cliente.servidor;

    C_Crear(&colaCorreos, sizeCorreo);

    cantCorreos = obtenerCorreos( aux , cliente.direccion , &colaCorreos);

    if ( !cantCorreos )
        return 0;

    while( !C_Vacia(colaCorreos) ){
        C_Sacar(&colaCorreos, &correo);

        desencriptarVignere(correo.cuerpo,cliente.clave,correo.cuerpo);

        if ( LC_Vacia(*correos) ){
            LC_Insertar(correos, LO_PRIMERO, &correo);

        }else{
            LC_Insertar(correos, LO_SIGUIENTE, &correo);
        }
    }

    printListaCorreo(correos);
    return cantCorreos;
}
